# -*- coding: utf-8 -*-
"""
    xfree.auth.plugins
    ~~~~~~~~~~~~~~~~~~~~~
    文件描述：xfree认证钩子的插件实现
    作者：xfree
    邮箱：cy_83k@qq.com
"""

from flask import flash, redirect, url_for
from flask_login import current_user, logout_user

# 从相关模块导入ForceLogout异常类
from..core.auth.authentication import ForceLogout
from..extensions import db
from..user.models import User
from..utils.settings import xfree_config
from. import impl
from.services.authentication import (
    BlockUnactivatedUser,  # 阻止未激活用户的类
    ClearFailedLogins,  # 清除失败登录记录的类
    DefaultxfreeAuthProvider,  # 默认的xfree认证提供器类
    MarkFailedLogin,  # 标记失败登录的类
)
from.services.factories import account_activator_factory
from.services.reauthentication import (
    ClearFailedLoginsOnReauth,  # 重新认证后清除失败登录记录的类
    DefaultxfreeReauthProvider,  # 默认的xfree重新认证提供器类
    MarkFailedReauth,  # 标记重新认证失败的类
)
from.services.registration import (
    AutoActivateUserPostProcessor,  # 自动激活用户后处理器类
    AutologinPostProcessor,  # 自动登录后处理器类
    EmailUniquenessValidator,  # 邮箱唯一性验证器类
    SendActivationPostProcessor,  # 发送激活邮件后处理器类
    UsernameRequirements,  # 用户名字段要求类
    UsernameUniquenessValidator,  # 用户名唯一性验证器类
    UsernameValidator,  # 用户名字段验证器类
)


# 使用impl装饰器（假设这是一个自定义的实现注册装饰器），并且设置trylast=True（可能表示在实现链中最后尝试）
@impl(trylast=True)
def xfree_authenticate(identifier, secret):
    """
    执行xfree认证的函数

    :param identifier: 用于识别用户的标识（例如用户名或邮箱）
    :param secret: 用户的密码或其他认证密钥
    :return: 认证结果（通常是用户对象或None）
    """
    return DefaultxfreeAuthProvider().authenticate(identifier, secret)


# 使用impl装饰器，并且设置tryfirst=True（可能表示在实现链中首先尝试）
@impl(tryfirst=True)
def xfree_post_authenticate(user):
    """
    认证后处理函数

    :param user: 已认证的用户对象
    """
    handlers = [ClearFailedLogins()]

    # 如果配置中要求激活账户
    if xfree_config["ACTIVATE_ACCOUNT"]:
        handlers.append(BlockUnactivatedUser())

    for handler in handlers:
        handler.handle_post_auth(user)


@impl
def xfree_authentication_failed(identifier):
    """
    处理认证失败的函数

    :param identifier: 用于识别用户的标识（例如用户名或邮箱）
    """
    MarkFailedLogin().handle_authentication_failure(identifier)


# 使用impl装饰器，并且设置trylast=True
@impl(trylast=True)
def xfree_reauth_attempt(user, secret):
    """
    尝试重新认证的函数

    :param user: 当前用户对象
    :param secret: 用户的密码或其他重新认证密钥
    :return: 重新认证结果（通常是用户对象或None）
    """
    return DefaultxfreeReauthProvider().reauthenticate(user, secret)


@impl
def xfree_reauth_failed(user):
    """
    处理重新认证失败的函数

    :param user: 当前用户对象
    """
    MarkFailedReauth().handle_reauth_failure(user)


@impl
def xfree_post_reauth(user):
    """
    重新认证后处理函数

    :param user: 已重新认证的用户对象
    """
    ClearFailedLoginsOnReauth().handle_post_reauth(user)


@impl
def xfree_errorhandlers(app):
    """
    注册错误处理函数

    :param app: Flask应用对象
    """
    @app.errorhandler(ForceLogout)
    def handle_force_logout(error):
        """
        处理强制登出的函数

        :param error: ForceLogout异常对象
        :return: 重定向到论坛首页
        """
        if current_user:
            logout_user()
            if error.reason:
                flash(error.reason, "danger")
        return redirect(url_for("forum.index"))


@impl
def xfree_gather_registration_validators():
    """
    收集注册验证器的函数
    """
    blacklist = [
        w.strip() for w in xfree_config["AUTH_USERNAME_BLACKLIST"].split(",")
    ]

    requirements = UsernameRequirements(
        min=xfree_config["AUTH_USERNAME_MIN_LENGTH"],
        max=xfree_config["AUTH_USERNAME_MAX_LENGTH"],
        blacklist=blacklist,
    )

    return [
        EmailUniquenessValidator(User),
        UsernameUniquenessValidator(User),
        UsernameValidator(requirements),
    ]


@impl
def xfree_registration_post_processor(user):
    """
    注册后处理器函数

    :param user: 新注册的用户对象
    """
    handlers = []

    if xfree_config["ACTIVATE_ACCOUNT"]:
        handlers.append(SendActivationPostProcessor(account_activator_factory()))
    else:
        handlers.append(AutologinPostProcessor())
        handlers.append(AutoActivateUserPostProcessor(db, xfree_config))

    for handler in handlers:
        handler.post_process(user)